home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / ms-0_06.lha / bms-0.06 / bms.c < prev    next >
C/C++ Source or Header  |  1991-11-09  |  10KB  |  390 lines

  1. /* bms.c - batch-mode MandelSpawn main program */
  2.  
  3. /*  This file is part of MandelSpawn, a parallel Mandelbrot program.
  4.  
  5.     Copyright (C) 1990, 1991 Andreas Gustafsson
  6.  
  7.     MandelSpawn is free software; you can redistribute it and/or modify
  8.     it under the terms of the GNU General Public License, version 1,
  9.     as published by the Free Software Foundation.
  10.  
  11.     MandelSpawn is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License,
  17.     version 1, along with this program; if not, write to the Free 
  18.     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. */
  20.  
  21. /* bsd43 is defined on Sonys, but not on MtXinu more/bsd.  You can't win. */
  22. #ifdef bsd43
  23. #ifndef NO_MALLOC_H
  24. #define NO_MALLOC_H
  25. #endif
  26. #endif
  27.  
  28. #ifdef _AIX
  29. #ifndef NEED_SYS_SELECT_H
  30. #define NEED_SYS_SELECT_H
  31. #endif
  32. #endif
  33.  
  34. /* 4.3 BSD wants these two for select() */
  35. #include <sys/types.h>
  36. #include <sys/time.h>
  37.  
  38. #include <stdio.h>
  39. #include <string.h>
  40. #include <errno.h>
  41. extern int errno; /* argh */
  42. #ifndef NO_MALLOC_H
  43. #include <malloc.h>
  44. #else
  45. char *malloc(), *realloc(); void free(); /* double argh */
  46. #endif
  47. #include <math.h> /* for atof() */
  48. #ifdef NEED_SYS_SELECT_H
  49. #include <sys/select.h>
  50. #endif
  51.  
  52. #include "work.h"
  53. #include "mspawn.h"
  54. #include "version.h"
  55.  
  56. #define TIMEOUT 15000    /* default computation server timeout in millisecs */
  57.  
  58. /* number of pixels to print on each line in the portable graymap file */
  59. /* (watch out for line length limit of 70 characters) */
  60. #define PGM_NPL 8 
  61.  
  62.  
  63. char *me;    /* name of program */
  64.  
  65.  
  66. /* various global mode flags */
  67.  
  68. int done = 0;        /* set when all chunks have arrived */
  69. int verbose = 0;    /* verbosity level */
  70. int statistics = 0;    /* print statistics if set */
  71. int pgm_ascii = 0;    /* force ASCII graymap format */
  72. int nooutput = 0;    /* generate no output (for testing only) */
  73.  
  74.  
  75. /* structure for global data */     
  76.  
  77. typedef struct bms_state
  78. { ms_state ms;
  79.   union
  80.   { unsigned char *bytes;
  81.     unsigned short *shorts;
  82.   } frame;
  83. } bms_state;
  84.  
  85.  
  86. /* report a fatal error and die */
  87.  
  88. void error(s) char *s;
  89. { fprintf(stderr, "%s: %s\n", me, s);
  90.   exit(1);
  91. }
  92.  
  93.  
  94. /* handle input from a computation server by drawing in an in-core buffer */
  95.  
  96. void ms_draw(client, client_data, data) /*ARGSUSED*/
  97.      char *client;    /* unused */
  98.      char *client_data;
  99.      char *data;
  100. { ms_client_info *the_info = (ms_client_info *) client_data;
  101.   bms_state *b = (bms_state *) client;
  102.   unsigned int x, y, width, height;
  103.   unsigned int i, j;
  104.   if(verbose)
  105.   { putc('.', stderr);
  106.     fflush(stderr);
  107.   }
  108.   x=the_info->s.x; 
  109.   y=the_info->s.y; 
  110.   width=the_info->s.width;
  111.   height=the_info->s.height;
  112.  
  113.   switch(b->ms.bytes_per_count)
  114.   { case 1:
  115.       { unsigned char *datap = (unsigned char *) data;
  116.     unsigned char *bufp_left= (unsigned char *)
  117.       b->frame.bytes + b->ms.width * y + x;
  118.     for(j=0; j<height; j++)
  119.     { unsigned char *bufp= bufp_left;
  120.       for(i=0; i<width; i++)
  121.       { *bufp++ = *datap++;
  122.       }
  123.       bufp_left += b->ms.width;
  124.     }
  125.       }
  126.       break;
  127.     case 2:
  128.       { unsigned short *datap = (unsigned short *) data;
  129.     unsigned short *bufp_left= (unsigned short *)
  130.       b->frame.shorts + b->ms.width * y + x;
  131.     for(j=0; j<height; j++)
  132.     { unsigned short *bufp= bufp_left;
  133.       for(i=0; i<width; i++)
  134.       { *bufp++ = *datap++;
  135.       }
  136.       bufp_left += b->ms.width;
  137.     }
  138.       }
  139.       break;
  140.     default:
  141.       error("bad iteration count size"); 
  142.       break;
  143.   }
  144.  
  145.   b->ms.chunks_out--; /* one less to go */
  146.   
  147.   if(b->ms.chunks_out == 0)
  148.     done=1;
  149. }
  150.  
  151.  
  152. /* provide memory allocation and error reporting services to the */
  153. /* workforce module */
  154.  
  155. char *wf_alloc(size) unsigned size;
  156. { char *r = malloc(size);
  157.   if(!r)
  158.     error("malloc");
  159.   return(r);
  160. }
  161.  
  162. char *wf_realloc(p, size) char *p; unsigned size;
  163. { char *r = realloc(p, size);
  164.   if(!r)
  165.     error("realloc");
  166.   return(r);
  167. }
  168.  
  169. void wf_free(p) char *p;
  170. { free(p);
  171. }
  172.  
  173. void wf_error(s) char *s;
  174. { error(s);
  175. }
  176.  
  177. void wf_warn(s) char *s;
  178. { fprintf(stderr, "warning: %s\n", s);
  179. }
  180.  
  181.  
  182. /* unique values to identify options */  
  183.  
  184. enum bms_opt
  185. { opt_height, opt_width, opt_x, opt_y, opt_range,
  186.     opt_julia, opt_colours, opt_cx, opt_cy,
  187.     opt_chunk_width, opt_chunk_height, opt_verbose,
  188.     opt_nooutput, opt_statistics, opt_version, opt_ascii
  189. };
  190.  
  191. struct option
  192. { enum bms_opt id;
  193.   char *name;
  194.   int has_arg;
  195. };
  196.  
  197. struct option options[] = 
  198. { { opt_height, "height", 1 }, 
  199.   { opt_width, "width", 1 },
  200.   { opt_x, "x", 1 },
  201.   { opt_y, "y", 1 },
  202.   { opt_range, "range", 1 },
  203.   { opt_julia, "julia", 0 },
  204.   { opt_colours, "colours", 1 },
  205.   { opt_colours, "colors", 1 },
  206.   { opt_colours, "iterations", 1 },
  207.   { opt_cx, "cx", 1 },
  208.   { opt_cy, "cy", 1 },
  209.   { opt_chunk_width, "chunk_width", 1 },
  210.   { opt_chunk_height, "chunk_height", 1 },
  211.   { opt_verbose, "verbose", 0 },
  212.   { opt_nooutput, "nooutput", 0 },
  213.   { opt_statistics, "statistics", 0 },
  214.   { opt_version, "version", 0 },
  215.   { opt_ascii, "ascii", 0 }
  216. };
  217.  
  218.  
  219. int main(argc, argv)
  220.      int argc; char **argv;
  221. { bms_state bms;
  222.   wf_state *workforce;
  223.   int isock;
  224.   int i,j; 
  225.   char *optarg;
  226.   fd_set readfds;
  227.   struct timeval tv, zero_tv;
  228.  
  229.   me=argv[0];
  230.  
  231.   /* defaults */
  232.   bms.ms.width = 64;
  233.   bms.ms.height = 24;
  234.   bms.ms.center_x = -0.5;
  235.   bms.ms.center_y = 0.0;
  236.   bms.ms.xrange = 4.0;
  237.   bms.ms.julia = 0;
  238.   /* bms.ms.c_x...*/
  239.   bms.ms.job.iteration_limit=250;
  240.  
  241.   bms.ms.chunk_height = bms.ms.chunk_width = 32;
  242.  
  243.   for(i=1; i<argc; i++)
  244.   { char *arg = argv[i];
  245.     if(*arg == '-')
  246.       for(j=0; j<sizeof(options)/sizeof(options[0]); j++)
  247.       { if(strcmp(arg+1, options[j].name) == 0)
  248.     { if(options[j].has_arg)
  249.       { if(argc < i)
  250.           error("option requires argument");
  251.         optarg = argv[++i];
  252.       }
  253.       switch(options[j].id)
  254.       { case opt_width: bms.ms.width=atoi(optarg); break;
  255.         case opt_height: bms.ms.height=atoi(optarg); break;
  256.         case opt_x: bms.ms.center_x=atof(optarg); break;
  257.         case opt_y: bms.ms.center_y=atof(optarg); break;
  258.         case opt_range: bms.ms.xrange=atof(optarg); break;
  259.          case opt_julia: bms.ms.julia=1; break;
  260.         case opt_colours: bms.ms.job.iteration_limit=atoi(optarg); break;
  261.         case opt_cx: bms.ms.c_x=atof(optarg); break;
  262.         case opt_cy: bms.ms.c_y=atof(optarg); break;
  263.         case opt_chunk_width: bms.ms.chunk_width=atoi(optarg); break;
  264.         case opt_chunk_height: bms.ms.chunk_height=atoi(optarg); break;
  265.         case opt_verbose: verbose++; break;
  266.         case opt_nooutput: nooutput++; break;
  267.         case opt_statistics: statistics++; break;
  268.         case opt_version:
  269.           printf("bms version %s\n", ms_version);
  270.           exit(0);
  271.           break;
  272.         case opt_ascii: pgm_ascii++; break;
  273.             default: error("internal option procesing error");
  274.       }
  275.       goto nextopt;
  276.     } /* if !strcmp */
  277.       } /* for j */
  278.     error("unrecognized option");
  279.    nextopt: ;
  280.   } /* for i */
  281.  
  282.   bms.ms.bytes_per_count = (bms.ms.job.iteration_limit > 256 ? 2 : 1);
  283.  
  284.   ms_init(&bms.ms, workforce = wf_init(TIMEOUT));
  285.   isock=wf_socket(workforce);
  286.  
  287.   ms_calculate_job_parameters(&bms.ms, &bms.ms.job);
  288.  
  289.   /* allocate memory for frame buffer */
  290.   switch(bms.ms.bytes_per_count)
  291.   { case 1:
  292.       bms.frame.bytes = (unsigned char *)
  293.     malloc(bms.ms.width * bms.ms.height * sizeof(unsigned char));
  294.       break;
  295.     case 2:
  296.       bms.frame.shorts = (unsigned short *)
  297.     malloc(bms.ms.width * bms.ms.height * sizeof(unsigned short));
  298.       break;
  299.     default:
  300.       error("bad iteration count size"); break;
  301.   }
  302.   
  303.   ms_dispatch_rect(&bms.ms, (char *) &bms, 0, 0, bms.ms.width, bms.ms.height);
  304.  
  305.   zero_tv.tv_sec=0;
  306.   zero_tv.tv_usec=0;
  307.   tv.tv_sec=1;
  308.   tv.tv_usec=0;
  309.  
  310.   /* main loop: receive replies and build the picture in memory */
  311.   while(! done)
  312.   { int nready;
  313.  
  314.     /* keep polling as long as there is data; it's no use bothering */
  315.     /* with timeouts if we're fully occupied handling incoming data */
  316.     do
  317.     {
  318.     redo_1:
  319.       FD_ZERO(&readfds);
  320.       FD_SET(isock, &readfds);
  321.       nready=select(isock+1, &readfds, NULL, NULL, &zero_tv);
  322.       if(nready== -1)
  323.       { if(errno==EINTR)
  324.       goto redo_1;
  325.     error("select");
  326.       }
  327.       else if(nready>0 && FD_ISSET(isock, &readfds))
  328.           wf_handle_socket_input(workforce, (char *) 0);
  329.     } while(nready);
  330.  
  331.     /* no more data; handle any pending timeouts and then go to sleep for */
  332.     /* a second or until new data arrive */
  333.     wf_tick(workforce);
  334.  
  335.   redo_2:
  336.     FD_ZERO(&readfds);
  337.     FD_SET(isock, &readfds);
  338.     nready=select(isock+1, &readfds, NULL, NULL, &tv);
  339.     if(nready== -1)
  340.     { if(errno==EINTR)
  341.     goto redo_2;
  342.       error("select");
  343.     }
  344.     else if(nready>0 && FD_ISSET(isock, &readfds))
  345.       wf_handle_socket_input(workforce, (char *) 0);
  346.   }
  347.  
  348.   /* we have received all the replies; write out the finished picture */
  349.   if(! nooutput)
  350.   { 
  351.     if(verbose)
  352.     { putc('\n', stderr);
  353.     }
  354.     if(bms.ms.bytes_per_count > 1 || pgm_ascii) /* ASCII pgm format */
  355.     { unsigned i, j;
  356.       printf("P2\n%d %d\n%d\n",
  357.          bms.ms.width, bms.ms.height, bms.ms.job.iteration_limit-1);
  358.       for(j=0; j<bms.ms.height; j++)
  359.       {    for(i=0; i<bms.ms.width; i++)
  360.       printf("%d%c",
  361.          bms.ms.bytes_per_count == 2 ? 
  362.              bms.frame.shorts[j*bms.ms.width+i] :
  363.            bms.frame.bytes[j*bms.ms.width+i],
  364.          i%PGM_NPL==(PGM_NPL-1) ? '\n' : ' ');
  365.     if(i%PGM_NPL)
  366.       putchar('\n');
  367.       }
  368.     }
  369.     else /* binary pgm format */
  370.     { unsigned i, j;
  371.       printf("P5\n%d %d\n%d\n", 
  372.          bms.ms.width, bms.ms.height, bms.ms.job.iteration_limit-1);
  373. #ifdef PARANOIA
  374.       for(j=0; j<bms.ms.height; j++)
  375.     for(i=0; i<bms.ms.width; i++)
  376.       putchar(bms.frame.bytes[j*bms.ms.width+i]);
  377. #else
  378.       /* we happen to use the same internal representation for the image */
  379.       /* as the data part of a binary pgm file, so we can dump it as such */
  380.       fwrite(bms.frame.bytes, sizeof(char),
  381.          bms.ms.width*bms.ms.height, stdout);
  382. #endif
  383.     }
  384.   }
  385.   if(statistics)
  386.   { wf_print_stats(workforce, stderr);
  387.   }
  388.   exit(0);
  389. }
  390.